/**
 * 
 */
package wong.board.client.widgets;

import java.util.ArrayList;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.DomEvent;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.HasText;
import com.google.gwt.user.client.ui.HasValue;

/**
 * @author wong
 * 
 */
public class Button<V> extends Component implements HasText, HasValue<V>, HasButtonCallbacks<V> {
	private ArrayList<ButtonCallback<V>> buttonCallbacks;
	private HandlerRegistration clickRegistration;
	private HandlerRegistration keyUpRegistration;
	private V value;

	protected Button() {
		setStyleName(css.button());
		getElement().setTabIndex(0);
	}

	public Button(V buttonData, String text) {
		this();
		this.value = buttonData;
		this.setText(text);
	}

	public Button(String text) {
		this(null, text);
	}

	public void setText(String text) {
		getElement().setInnerText(text);
	}

	@Override
	public String getText() {
		return getElement().getInnerText();
	}

	@Override
	public void addCallback(ButtonCallback<V> callback) {
		if (buttonCallbacks == null) {
			buttonCallbacks = new ArrayList<Button.ButtonCallback<V>>();
		}
		buttonCallbacks.add(callback);
	}

	@Override
	public void removeCallback(ButtonCallback<V> callback) {
		if (buttonCallbacks == null) {
			return;
		}
		buttonCallbacks.remove(callback);
	}

	protected void callAction(DomEvent<?> event) {
		if (buttonCallbacks == null) {
			return;
		}
		for (ButtonCallback<V> action : buttonCallbacks) {
			action.onAction(this, event);
		}
	}

	@Override
	protected void onAttach() {
		super.onAttach();
		UIHandler handler = new UIHandler();
		clickRegistration = this.addDomHandler(handler, ClickEvent.getType());
		keyUpRegistration = this.addDomHandler(handler, KeyUpEvent.getType());
	}

	@Override
	protected void onDetach() {
		clickRegistration.removeHandler();
		clickRegistration = null;
		keyUpRegistration.removeHandler();
		keyUpRegistration = null;
		super.onDetach();
	}

	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<V> handler) {
		return super.addHandler(handler, ValueChangeEvent.getType());
	}

	@Override
	public V getValue() {
		return value;
	}

	@Override
	public void setValue(V value) {
		setValue(value, true);
	}

	@Override
	public void setValue(V value, boolean fireEvents) {
		if (value != null && this.value != null && value.equals(this.value)) {
			return;
		}
		if (fireEvents) {
			ValueChangeEvent.fire(this, value);
		}
		this.value = value;
	}

	/* */

	public interface ButtonCallback<V> {
		void onAction(Button<V> button, DomEvent<?> event);
	}

	private class UIHandler implements ClickHandler, KeyUpHandler {

		@Override
		public void onClick(ClickEvent event) {
			Button.this.callAction(event);
		}

		@Override
		public void onKeyUp(KeyUpEvent event) {
			if (event.getNativeKeyCode() == 32 || event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
				Button.this.callAction(event);
			}
		}

	}

}
